package br.ufc.customJDBC.routing;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import br.ufc.customJDBC.CustomConnection;
import br.ufc.customJDBC.csv.CSVLog;

class CheckStateProvisioning extends TimerTask {
	private ProvisioningRouter rpr;
	public CheckStateProvisioning(ProvisioningRouter rpr){
		this.rpr = rpr;
	}
	public void run() {
		rpr.checkState();
	}
}

public class ProvisioningRouter implements Router{
	
	private static ProvisioningRouter singleton = null;

	private Timer timer;
	public static long ms = 1000000;
	public static long sec = 1000000000;
	private List<Integer> history;
	private Iterator<Integer> iter;

	private List<CustomConnection> fullConnectionPool;
	private List<CustomConnection> connectionPool;
	private int connectionPoolSize;
	private CSVLog csv;

	private ProvisioningRouter(Collection<CustomConnection> connectionPool, 
			long sla, long min, CSVLog csv, List<Integer> history) {
		this.fullConnectionPool = new ArrayList<CustomConnection>(connectionPool);
		this.connectionPool = fullConnectionPool.subList(0, 1);
		this.connectionPoolSize = this.connectionPool.size();
		this.history = history;
		iter = history.iterator();
		System.out.println("Provisioning Router:");
		System.out.println("Number of nodes: " + this.connectionPoolSize);
		System.out.println("Connections:");
		for(CustomConnection cc : this.connectionPool){
			System.out.println(cc.getIp());
		}		
		startTimer();
		this.csv = csv;
	}
	
	private void startTimer(){
		this.timer = new Timer();
		timer.scheduleAtFixedRate(new CheckStateProvisioning(this), 0, 1000);
	}
	
	public static ProvisioningRouter getInstance(Collection<CustomConnection> connectionPool, 
			long sla, long min, CSVLog csv, List<Integer> history){
		if(singleton == null){
			singleton = new ProvisioningRouter(connectionPool, sla, min, csv, history);
			return singleton;
		}else{
			return singleton;
		}
	}

	private CustomConnection nextConnection(){
		Random rand = new Random();
		int randomNum = rand.nextInt(connectionPoolSize);
		return connectionPool.get(randomNum);
	}

	public void checkState(){
		if(iter.hasNext()){
			Integer size = iter.next();
			resizeResource(size);
		}else{
			System.out.println("History is over");
		}
		
	}
	public void resizeResource(int newSize){
		System.out.println("Resize Resource");
		System.out.println("newSize: " + newSize);
		if(newSize > fullConnectionPool.size()){
			newSize = fullConnectionPool.size();
		}
		if(newSize < 1){
			newSize = 1;
		}
		if(connectionPoolSize != newSize ){
			connectionPool = fullConnectionPool.subList(0, newSize);
			connectionPoolSize = connectionPool.size();
		}		
		System.out.println("connectionPoolSize: " + connectionPoolSize);
	}

	@Override
	public ResultSet executeQuery(String sql) throws SQLException {
		CustomConnection con = nextConnection();
		Statement statement = con.createStatement();

		long startTime = System.nanoTime();
		ResultSet ret = statement.executeQuery(sql);
		long stopTime = System.nanoTime();

		String nodes = "[ " + con.getIp() + " ]";
		csv.writeLine(sql, (stopTime - startTime), 1, "executeQuery", nodes, connectionPoolSize );
		//		statement.close();
		return ret;
	}
	
	@Override
	public boolean execute(String sql) throws SQLException {

		CustomConnection con = nextConnection();
		Statement statement = con.createStatement();

		long startTime = System.nanoTime();
		boolean ret = statement.execute(sql);
		long stopTime = System.nanoTime();


		String nodes = "[ " + con.getIp() + " ]";
		csv.writeLine(sql, stopTime - startTime, 1, "execute", nodes, connectionPoolSize );
		//		statement.close();
		return ret;
	}

	@Override
	public int executeUpdate(String sql) throws SQLException {
		CustomConnection con = nextConnection();
		Statement statement = con.createStatement();

		long startTime = System.nanoTime();
		int ret = statement.executeUpdate(sql);
		long stopTime = System.nanoTime();

		String nodes = "[ " + con.getIp() + " ]";
		csv.writeLine(sql, (stopTime - startTime), 1, "executeUpdate", nodes, connectionPoolSize );

		//		statement.close();
		return ret;
	}
}

